package org.schhx.session;

import org.schhx.utils.ParameterMapping;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author shanchao
 * @date 2021/1/30
 */
public class SimpleExecutor implements Executor {


    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter) throws Exception {
        PreparedStatement preparedStatement = buildPreparedStatement(ms, parameter);

        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = ms.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);

        List<Object> objects = new ArrayList<>();

        while (resultSet.next()) {
            Object o = resultTypeClass.newInstance();
            //元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {

                // 字段名
                String columnName = metaData.getColumnName(i);
                // 字段的值
                Object value = resultSet.getObject(columnName);

                //使用反射或者内省，根据数据库表和实体的对应关系，完成封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, value);
            }
            objects.add(o);
        }

        return (List<E>) objects;
    }

    @Override
    public int update(MappedStatement ms, Object parameter) throws Exception {
        PreparedStatement preparedStatement = buildPreparedStatement(ms, parameter);
        return preparedStatement.executeUpdate();
    }

    private Class<?> getClassType(String className) throws ClassNotFoundException {
        if (className != null) {
            return Class.forName(className);
        }
        return null;
    }

    private PreparedStatement buildPreparedStatement(MappedStatement ms, Object parameter) throws Exception {
        Configuration configuration = ms.getConfiguration();

        BoundSql boundSql = ms.getBoundSql();

        Connection connection = configuration.getDataSource().getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());

        List<Object> parameters = new ArrayList<>();
        if (boundSql.getParameterMappings() != null && !boundSql.getParameterMappings().isEmpty()) {
            String parameterType = ms.getParameterType();
            Class parameterTypeClass = getClassType(parameterType);
            if (parameterTypeClass == null) {
                parameters.add(parameter);
            } else {
                for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
                    //反射
                    Field declaredField = parameterTypeClass.getDeclaredField(parameterMapping.getContent());
                    //暴力访问
                    declaredField.setAccessible(true);
                    parameters.add(declaredField.get(parameter));
                }
            }
        }

        for (int i = 0; i < parameters.size(); i++) {
            preparedStatement.setObject(i + 1, parameters.get(i));
        }
        return preparedStatement;
    }
}
